package com.ctshk.rpc.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.IsDeletedCode;
import com.ctshk.common.enums.OrderSource;
import com.ctshk.common.enums.SystemBusinessType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.air.service.app.IAirProductAppService;
import com.ctshk.rpc.hotel.service.IHotelH5Service;
import com.ctshk.rpc.localfun.dto.LocalFunProductDetailsResDTO;
import com.ctshk.rpc.localfun.req.LocalFunProductDetailsQueryReq;
import com.ctshk.rpc.localfun.service.ILocalFunAppProductService;
import com.ctshk.rpc.order.tour.code.OrderTypeCode;
import com.ctshk.rpc.tour.dto.TripDetailsH5ResDTO;
import com.ctshk.rpc.tour.dto.cache.TripsRecommendDTO;
import com.ctshk.rpc.tour.service.ISeriesTripAppService;
import com.ctshk.rpc.train.dto.TrainProductDTO;
import com.ctshk.rpc.train.service.ITrainProductService;
import com.ctshk.rpc.user.dto.UserFootPointGroupDTO;
import com.ctshk.rpc.user.dto.UserFootPointListDTO;
import com.ctshk.rpc.user.entity.UserCollection;
import com.ctshk.rpc.user.entity.UserFootPoint;
import com.ctshk.rpc.user.mapper.UserFootPointMapper;
import com.ctshk.rpc.user.req.*;
import com.ctshk.rpc.user.service.IUserFootPointService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * </p>
 *
 * @author 李新科
 * @date 2021/5/20 18:20
 */
@Slf4j
@DubboService
public class UserFootPointServiceImpl extends ServiceImpl<UserFootPointMapper, UserFootPoint> implements IUserFootPointService {

    @Autowired
    private UserFootPointMapper userFootPointMapper;

    @DubboReference
    private ISeriesTripAppService seriesTripAppService;

    @DubboReference
    private IHotelH5Service hotelH5Service;

    @DubboReference
    private ILocalFunAppProductService localFunAppProductService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Result<PageResponse<UserFootPointListDTO>> queryPage(UserFootPointPageReq req) {
        Page<UserFootPoint> queryPage = new Page(req.getPageNo(), req.getPageSize());
        Page<UserFootPoint> page = userFootPointMapper.selectPage(queryPage, new QueryWrapper<UserFootPoint>()
                .lambda().eq(UserFootPoint::getUserId, req.getUserId())
                .eq(UserFootPoint::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(UserFootPoint::getGmtCreate, LocalDateTime.now().minusDays(7))
                .groupBy(UserFootPoint::getDetailId));

        List<UserFootPointListDTO> listDTOS = EntityUtil.copyList(page.getRecords(), UserFootPointListDTO.class);
        PageResponse<UserFootPointListDTO> result = new PageResponse<>(listDTOS,
                page.getCurrent() == 1, page.getTotal() <= (page.getCurrent() *
                page.getSize()), page.getTotal(), page.getCurrent(), page.getSize());
        return Result.success(result);
    }

    @Override
    public CompletableFuture<Result> add(UserFootPointReq req) {
        return CompletableFuture.supplyAsync(() -> {
            Integer count = userFootPointMapper.selectCount(Wrappers.<UserFootPoint>lambdaQuery()
                    .eq(UserFootPoint::getDetailId, req.getDetailId())
                    .eq(UserFootPoint::getUserId, req.getUserId())
                    .eq(UserFootPoint::getIsDeleted, IsDeletedCode.NO.getCode()));
            UserFootPoint entity = EntityUtil.copy(req, UserFootPoint.class);
            redisTemplate.opsForHash().put(RedisConstants.FOOT_POINT_USER_ID + req.getUserId(), req.getDetailId().toString(),entity);
            // 设置七天过期
            redisTemplate.expire(RedisConstants.FOOT_POINT_USER_ID + req.getUserId(), 7, TimeUnit.DAYS);
            if(count == 0) {
                LocalDateTime now = LocalDateTime.now();
                Long userId = req.getUserId();
                entity.setId(SnowflakeIdWorker.nextId());
                entity.setUserId(userId);
                entity.setCreateId(userId);
                entity.setGmtCreate(now);
                entity.setGmtModified(now);
                entity.setIsDeleted(IsDeletedCode.NO.getCode());
                userFootPointMapper.insert(entity);
                entity.setGmtCreate(null);
                entity.setGmtModified(null);
            }
            return Result.success();
        });
    }

    @Override
    public CompletableFuture<Result> add(Serializable serializable) {
        return null;
    }

    @Override
    public Result delete(Long id, Long userId) {
        userFootPointMapper.delete(new QueryWrapper<UserFootPoint>()
                .lambda().eq(UserFootPoint::getId, id)
                .eq(UserFootPoint::getCreateId, userId));
        return Result.success();
    }

    @Override
    public Result deleteAll(Long userId) {
        userFootPointMapper.delete(new QueryWrapper<UserFootPoint>()
                .lambda().eq(UserFootPoint::getCreateId, userId));
        return Result.success();
    }

    @Override
    public Result<PageResponse<UserFootPointGroupDTO>> listGroupByDate(UserFootPointPageReq req) {
        Page<UserFootPoint> queryPage = new Page(req.getPageNo(), req.getPageSize());
        Page<UserFootPoint> page = userFootPointMapper.selectPage(queryPage, new QueryWrapper<UserFootPoint>()
                .lambda().eq(UserFootPoint::getUserId, req.getUserId())
                .eq(UserFootPoint::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(UserFootPoint::getGmtCreate, LocalDateTime.now().minusDays(7))
                .groupBy(UserFootPoint::getDetailId)
                .orderByDesc(UserFootPoint::getId));
        List<UserFootPoint> records = page.getRecords();
        List<UserFootPointGroupDTO> list = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(records)) {
            String dateStr = "";
            int index = 0;
            for (UserFootPoint record : records) {
                String recordDateStr = record.getGmtCreate().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日"));
                UserFootPointListDTO dto = EntityUtil.copy(record, UserFootPointListDTO.class);
                if(dateStr.equals(recordDateStr)) {
                    UserFootPointGroupDTO userFootPointGroupDTO = list.get(index - 1);
                    userFootPointGroupDTO.getUserFootPointList().add(dto);
                } else {
                    UserFootPointGroupDTO userFootPointGroupDTO = new UserFootPointGroupDTO();
                    userFootPointGroupDTO.setDate(recordDateStr);
                    userFootPointGroupDTO.setUserFootPointList(Lists.newArrayList(dto));
                    list.add(userFootPointGroupDTO);
                    index++;
                    dateStr = recordDateStr;
                }
            }
        }

        PageResponse<UserFootPointGroupDTO> result = new PageResponse<>(list,
                page.getCurrent() == 1, page.getTotal() <= (page.getCurrent() *
                page.getSize()), page.getTotal(), page.getCurrent(), page.getSize());
        return Result.success(result);
    }

    @Override
    public Integer countByUserId(Long userId) {
        Integer count = baseMapper.selectCount(new QueryWrapper<UserFootPoint>()
                .select("DISTINCT DETAIL_ID").lambda()
                .eq(UserFootPoint::getUserId, userId)
                .eq(UserFootPoint::getIsDeleted, IsDeletedCode.NO.getCode())
                .ge(UserFootPoint::getGmtCreate, LocalDateTime.now().minusDays(7))
        );

        return count == null?0:count;
    }

    @Override
    public Result<UserFootPointListDTO> detail(UserFootPointReq req) {
        List<UserFootPoint> userFootPoints = baseMapper.selectList(Wrappers.<UserFootPoint>lambdaQuery()
                .eq(UserFootPoint::getDetailId, req.getDetailId())
                .eq(UserFootPoint::getUserId, req.getUserId())
                .orderByDesc(UserFootPoint::getId));
        if(CollectionUtils.isNotEmpty(userFootPoints)) {
            return Result.success(EntityUtil.copy(userFootPoints.get(0), UserFootPointListDTO.class));
        }
        return null;
    }
}
